package com.mazaiting.manager.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mazaiting.auth.constant.AuthConstant;
import com.mazaiting.common.core.domain.result.ResultCode;
import com.mazaiting.common.core.ex.exceptions.BaseException;
import com.mazaiting.common.core.ex.exceptions.BusinessException;
import com.mazaiting.common.core.ex.exceptions.EmptyObjectException;
import com.mazaiting.web.holder.SpringContextHolder;
import com.mazaiting.manager.convert.IPermissionConverter;
import com.mazaiting.manager.domain.entity.SysPermission;
import com.mazaiting.manager.domain.form.PermForm;
import com.mazaiting.manager.domain.query.PermPageQuery;
import com.mazaiting.manager.domain.vo.permission.PermDetailVO;
import com.mazaiting.manager.domain.vo.permission.PermPageVO;
import com.mazaiting.manager.listeners.event.RuleRelationEvent;
import com.mazaiting.manager.mapper.ISysPermissionMapper;
import com.mazaiting.manager.service.ISysPermissionService;
import com.mazaiting.mybatisplus.domain.vo.BasePageVO;
import com.mazaiting.redis.service.IRedisService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * <p>
 * 权限表 服务实现类
 * </p>
 *
 * @author mazaiting
 * @since 2022-09-08
 */
@Service
@RequiredArgsConstructor
public class SysPermissionServiceImpl extends ServiceImpl<ISysPermissionMapper, SysPermission> implements ISysPermissionService {

    private final IPermissionConverter permissionConverter;

    private final IRedisService redisService;

    @Override
    public BasePageVO<PermPageVO> listPermPages(PermPageQuery queryParams) {
        // 分页对象
        Page<PermPageVO> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
        // 获取分页数据
        List<PermPageVO> list = this.baseMapper.listPermPages(page, queryParams);
        page.setRecords(list);

        return BasePageVO.success(page);
    }

    @Override
    public boolean save(PermForm permForm) throws BusinessException {
        // 取权限
        String urlPerm = permForm.getUrlPerm();
        String btnPerm = permForm.getBtnPerm();

        // 查询菜单 ID 对应的 URL 权限 / BTN 权限是否存在
        Optional<SysPermission> sysPermissionOpt = lambdaQuery().eq(SysPermission::getMenuId, permForm.getMenuId())
                .and(StringUtils.hasLength(urlPerm) || StringUtils.hasLength(btnPerm),
                        sysPermissionLambdaQueryWrapper -> sysPermissionLambdaQueryWrapper
                                .eq(StringUtils.hasLength(urlPerm), SysPermission::getUrlPerm, urlPerm)
                                .or()
                                .eq(StringUtils.hasLength(btnPerm), SysPermission::getBtnPerm, btnPerm)).oneOpt();
        if (sysPermissionOpt.isPresent()) {
            throw new BusinessException(ResultCode.PERMISSION_EXIST);
        }

        // form -> entity
        SysPermission sysPermission = permissionConverter.form2Entity(permForm);
        sysPermission.setId(null);

        // 保存
        boolean result = save(sysPermission);
        if (result) {
            SpringContextHolder.publishEvent(new RuleRelationEvent());
        }
        return result;
    }

    @Override
    public boolean update(PermForm permForm) throws BaseException {
        // 根据 ID 获取权限
        SysPermission sysPermission = getById(permForm.getId());
        if (Objects.isNull(sysPermission)) {
            throw new EmptyObjectException(ResultCode.PERMISSION_NOT_EXIST);
        }

        // 取权限
        String urlPerm = permForm.getUrlPerm();
        String btnPerm = permForm.getBtnPerm();

        // 查询菜单 ID 对应的 URL 权限 / BTN 权限是否存在
        Optional<SysPermission> sysPermissionOpt = lambdaQuery()
                .ne(SysPermission::getId, permForm.getId())
                .eq(SysPermission::getMenuId, permForm.getMenuId())
                .and(StringUtils.hasLength(urlPerm) && StringUtils.hasLength(btnPerm),
                        sysPermissionLambdaQueryWrapper -> sysPermissionLambdaQueryWrapper
                                .eq(StringUtils.hasLength(urlPerm), SysPermission::getUrlPerm, urlPerm)
                                .or()
                                .eq(StringUtils.hasLength(btnPerm), SysPermission::getBtnPerm, btnPerm)).oneOpt();
        if (sysPermissionOpt.isPresent()) {
            throw new BusinessException(ResultCode.PERMISSION_EXIST);
        }

        // form -> entity
        permissionConverter.form2Entity(permForm, sysPermission);

        // 保存
        boolean result = updateById(sysPermission);
        if (result) {
            SpringContextHolder.publishEvent(new RuleRelationEvent());
        }
        return result;
    }

    @Override
    public boolean deleteByIds(String ids) {
        // 转换字符串 ids 为 id 列表
        List<Long> idList = Arrays.stream(ids.split(",")).mapToLong(Long::parseLong).boxed().toList();
        boolean result = removeBatchByIds(idList);
        if (result) {
            SpringContextHolder.publishEvent(new RuleRelationEvent());
        }
        return result;
    }

    /**
     * 权限<->有权限的角色集合
     *
     * @return 权限<->有权限的角色集合
     */
    @Override
    public List<SysPermission> listPermRoles() {
        return baseMapper.listPermRoles();
    }

    @Override
    public boolean reloadPermRolesRules() {
        // 删除缓存
        redisService.del(Arrays.asList(AuthConstant.URL_PERM_ROLES_KEY, AuthConstant.BTN_PERM_ROLES_KEY));
        // 获取权限+角色集合
        List<SysPermission> permissions = listPermRoles();
        if (CollectionUtil.isNotEmpty(permissions)) {
            // 初始化URL【URL权限->角色(集合)】规则
            List<SysPermission> urlPermList = permissions.stream()
                    .filter(item -> StringUtils.hasLength(item.getUrlPerm()))
                    .toList();
            if (CollectionUtil.isNotEmpty(urlPermList)) {
                Map<String, List<String>> urlPermRoles = new HashMap<>();
                urlPermList.forEach(item -> urlPermRoles.put(item.getUrlPerm(), item.getRoles()));
                redisService.hSetAll(AuthConstant.URL_PERM_ROLES_KEY, urlPermRoles);
            }
            // 初始化URL【BTN权限->角色(集合)】规则
            List<SysPermission> btnPermList = permissions.stream()
                    .filter(item -> StringUtils.hasLength(item.getBtnPerm()))
                    .toList();
            if (CollectionUtil.isNotEmpty(btnPermList)) {
                Map<String, List<String>> btnPermRoles = new HashMap<>();
                btnPermList.forEach(item -> btnPermRoles.put(item.getBtnPerm(), item.getRoles()));
                redisService.hSetAll(AuthConstant.BTN_PERM_ROLES_KEY, btnPermRoles);
            }
        }
        return true;
    }

    @Override
    public PermDetailVO getDetailById(Long permissionId) throws EmptyObjectException {
        SysPermission sysPermission = getById(permissionId);
        if (Objects.isNull(sysPermission)) {
            throw new EmptyObjectException(ResultCode.PERMISSION_NOT_EXIST);
        }
        return permissionConverter.entity2VO(sysPermission);
    }
}
